package cn.xuqiudong.console.module.backup.helper.baidu;

import cn.xuqiudong.common.base.craw.BaseCrawl;
import cn.xuqiudong.common.base.craw.CrawlConnect;
import cn.xuqiudong.common.base.vo.BooleanWithMsg;
import cn.xuqiudong.console.module.backup.helper.baidu.model.FileListQuery;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.jsoup.Connection;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

/**
 * 描述: 百度云盘工具类
 * @author Vic.xu
 * @since 2024-01-31 14:50
 */
@Component
public class BaiduPanHelper extends BaseCrawl {

    private static final Logger LOGGER = LoggerFactory.getLogger(BaiduPanHelper.class);

    private static final String BASE_BAIDU_URL = "https://openapi.baidu.com/oauth/2.0";

    private static final String BASE_BAIDU_API_PREFIX = "https://pan.baidu.com";

    /**
     * 上传的根路径
     */
    private static final String ROOT_PATH = "/apps/home-linux";

    private static ObjectMapper mapper = new ObjectMapper();

    @Autowired
    private BaiduPanConfig baiduPanConfig;


    @Override
    protected int getTimeout() {
        return 30000;
    }


    public BaiduPanProperties getAndCheckBaiduPanProperties(){
        BaiduPanProperties panProperties = baiduPanConfig.getBaiduPanProperties();
        if (panProperties.isExpired()) {
            try {
                this.refreshToken();
                panProperties = baiduPanConfig.getBaiduPanProperties();
            } catch (IOException e) {
                LOGGER.error("refreshToken error", e);
            }
        }
        return panProperties;
    }

    /**
     * 刷新token
     * <a href="https://pan.baidu.com/union/doc/al0rwqzzl">刷新 Access Token</a>
     * 响应示例：
     * {
     *   expires_in: 2592000,  // Access Token的有效期，单位为秒。
     *   refresh_token: "122.51265f007055bc895cb02c639410a90d.YDLFcE2nee3Cyu-Bsn7SAFVCAfdCkvSm4EnCdkO.Zs_FiQ",  //用于刷新Access Token, 有效期为10年。
     *   access_token: "121.60bf4c9911cb554aac39a1c701a4dae8.YDjwYds0zFgbM1rifQhjMLwsfb6xYus5tUhNEoA.XNNoOQ",
     *   session_secret: "",
     *   session_key: "",
     *   scope: "basic netdisk"
     * }
     */
    public void refreshToken() throws IOException {
        String refreshTokenUrl = BASE_BAIDU_URL + "/token?grant_type=refresh_token";
        BaiduPanProperties panProperties = baiduPanConfig.getBaiduPanProperties();
        CrawlConnect crawlConnect = con(refreshTokenUrl)
                .data("refresh_token", panProperties.getRefreshToken())
                .data("client_id", panProperties.getAppKey())
                .data("client_secret", panProperties.getSecretKey());
        String bodyText = crawlConnect.getBodyText();
        LOGGER.info("refresh token result: {}", bodyText);
        JsonNode root = mapper.readTree(bodyText);


        JsonNode refreshTokenNode = root.at("/refresh_token");
        if (refreshTokenNode.isMissingNode()) {
            LOGGER.warn("refresh token  node missing");
            return;
        }
        String refreshToken = refreshTokenNode.asText();
        String accessToken = root.at("/access_token").asText();
        long expiresIn = root.at("/expires_in").asLong();
        baiduPanConfig.updateBaiduYunConfig(refreshToken, accessToken, expiresIn);
        LOGGER.info("refresh token successfully");

    }

    /**
     * 获取用户信息
     */
    public void userInfo() throws IOException {
        String url = BASE_BAIDU_API_PREFIX + "/rest/2.0/xpan/nas?method=uinfo";
        BaiduPanProperties panProperties = getAndCheckBaiduPanProperties();
        String userInfo = con(url).data("access_token", panProperties.getAccessToken())
                .getBodyText();
        /*
        响应示例
        {
            "avatar_url": "https://dss0.bdstatic.com/7Ls0a8Sm1A5BphGlnYG/sys/portrait/item/netdisk.1.3d20c095.phlucxvny00WCx9W4kLifw.jpg",
            "baidu_name": "百度用户A001",
            "errmsg": "succ",
            "errno": 0,
            "netdisk_name": "netdiskuser",
            "request_id": "674030589892501935",
            "uk": 208281036,
            "vip_type": 0
}
         */
        LOGGER.info("userInfo successfully: {}", userInfo);
    }

    /**
     * 获取网盘容量信息
     */
    public void capacity() throws IOException {
        String url = BASE_BAIDU_API_PREFIX + "/api/quota";
        BaiduPanProperties panProperties = getAndCheckBaiduPanProperties();
        String userInfo = con(url).data("access_token", panProperties.getAccessToken())
                .data("checkfree", "1")
                .getBodyText();
        /*
        响应示例
           {
            "errno": 0,
            "total": 2205465706496,
            "free": 2205465706496, //单位b
            "request_id": 4890482559098510375,
            "expire": false,
            "used": 686653888910
        }
         */
        LOGGER.info("capacity successfully: {}", userInfo);
    }

    /**
     * 获取文件列表
     * @param query FileListQuery
     * 错误码	错误描述
     * -7	文件或目录无权访问
     * -9	文件或目录不存在
     *
     */
    public void fileList(FileListQuery query) throws IOException {
        String url = BASE_BAIDU_API_PREFIX + "/rest/2.0/xpan/file?method=list";
        LOGGER.info("query map {}", query.toMap());
        BaiduPanProperties panProperties = getAndCheckBaiduPanProperties();
        String fileListText = con(url).data("access_token", panProperties.getAccessToken())
                .data(query.toMap())
                .getBodyText();
        /*
        {
            "errno": 0,
            "guid_info": "",
            "list": [{
                "server_filename": "abc",
                "privacy": 0,
                "category": 6,
                "unlist": 0,
                "fs_id": 770693330924692,
                "dir_empty": 1,
                "server_atime": 0,
                "server_ctime": 1596078019,
                "local_mtime": 1596078019,
                "size": 0,
                "isdir": 1,
                "share": 0,
                "path": "/测试目录/abc",
                "local_ctime": 1596078019,
                "server_mtime": 1596078019,
                "empty": 0,
                "oper_id": 2082810368
                }],
            "request_id": 4904657509137213829,
            "guid": 0
}
         */
        LOGGER.info("obtain fileList successfully: {}", fileListText);
    }

    /**
     * 单步上传;上传文件大小上限为2GB
     *  文件上传路径冲突的时候固定为 overwrite处理方式
     *
     * 错误码	错误描述	排查方向
     * 31024	没有申请上传权限	申请开通上传权限
     * 31061	文件已存在	文件已存在
     * 31064	上传路径权限	path 上传文件的绝对路径格式：/apps/申请接入时填写的产品名称请参考《能力说明->限制条件->目录限制》
     */
    public BooleanWithMsg upload(String path, File file) {
        try (InputStream in = new FileInputStream(file)){
            LOGGER.info("进入上传文件到百度云盘,path={}", path);
            BaiduPanProperties panProperties = getAndCheckBaiduPanProperties();

            String url = "https://d.pcs.baidu.com/rest/2.0/pcs/file?method=upload";
            // 把 \ 转为 /
            path = path.replace("\\", "/");
            path = ROOT_PATH + (path.startsWith("/") ? path : ("/" + path));

            url += "&access_token=" + panProperties.getAccessToken()
                    // 上传的文件绝对路径  /apps/appName/filename.jpg
                    + "&path=" + path
                    + "&ondup=overwrite"
            ;
            CrawlConnect connect = con(url)
                    .data("file", file.getName(), in)
                    .method(Connection.Method.POST);
            Connection.Response execute = connect.execute();
            String s = execute.parse().body().text();
            LOGGER.info("upload successfully: {}", s);
            return BooleanWithMsg.success(path);
        } catch (Exception e) {

            e.printStackTrace();
            System.out.println("-----------");
            LOGGER.error(e.getMessage(), e);
            return BooleanWithMsg.fail(e.getMessage());
        }
    }
}
